\setcounter{chapter}{2}

\chapter{本文算法}
\label{sec:CoreAlgorithm}
本章将从算法概述、算法核心细节及其他算法实现细节这三个方面介绍本文算法。算法概述部分重点分析IBL实时渲染方面存在的问题，然后
详细阐述本文算法解决这些问题的基本思路及难点。算法核心细节部分重点介绍本文算法核心部分的实现细节。其他算法实现细节部分简要介
绍本文算法非核心部分的实现细节。

\section{算法概述}
本节将详细阐述本文算法需要解决的问题、基本思想、难点及处理流程。具体介绍流程如下，首先介绍IBL实时渲染方面存在的问题，然后详
细阐述本文算法解决上述问题的基本思路和难点，最后介绍本文算法的处理流程。

\subsection{问题分析(大而全version，后期根据创新点精细化)}
自\citet{2012Physically}将IBL引入PBR系统后，有效地捕捉了环境的全局光照，大大增强了渲染结果的真实感。然而，将环境光纳入计
算后，光照计算复杂度随之增加，性能也随之下降，远不能达到实时渲染的要求。

环境光照的计算可分为漫反射光照与镜面反射光照两部分：

\begin{equation}
	L_{0}(p,\omega_{0})=\int_{\Omega }(k_{d}\frac{c}{\pi})L_{i}(p,\omega_{i})n\cdot w_{i}d\omega_{i}+\int_{\Omega }(k_{s}\frac{DFG}{4(\omega_{0}\cdot{n})(\omega_{i}\cdot{n})})L_{i}(p,\omega_{i})n\cdot w_{i}d\omega_{i} 
\end{equation}

对于前半部分漫反射光照来说，其积分计算仅与入射光线方向$\omega_{i}$有关。对于每一个像素，只需采样其表面半球所有入射的环境光
便可计算得出辐照度结果。因此通常根据黎曼和方法近似求解，预计算漫反射光照积分计算结果，将其存储至一张称为辐照度贴图的立方体贴
图中。渲染时只需通过$\omega_{0}$观察方向采样辐照度贴图，便可实时得到漫反射辐照度。

镜面反射光照的积分计算，一方面涉及入射光方向$\omega_{i}$与观察方向$\omega_{0}$两个未知量,均需运行时获取，无法直接求解。另
一方面相比于漫反射光照，镜面高光属于高频信号，光照效果细节颇多，若直接使用黎曼和近似求解积分会导致较大的误差，效果不佳。因此
无法类似于漫反射光照一般使用黎曼和近似求解预先计算辐照度贴图。因此，如何在保证光照质量的同时，以实时速率渲染镜面高光，便成为
了IBL实时渲染的技术瓶颈。


\subsection{本文算法基本思想}

关注镜面反射积分计算：

\begin{equation}
	\label{equation:specular}
	L_{0}(p,\omega_{0})=\int_{\Omega }(k_{s}\frac{DFG}{4(\omega_{0}\cdot{n})(\omega_{i}\cdot{n})})L_{i}(p,\omega_{i})n\cdot w_{i}d\omega_{i} 
\end{equation}

可以发现，由于镜面高光的积分计算不仅涉及入射光方向$\omega_{i}$，而且与观察方向$\omega_{0}$有关，实时计算两者的所有可能组合
的代价过于高昂。因此，我们无法以合理的性能实时求解该镜面反射积分。若能类似漫反射光照一样，预先计算镜面反射积分，便可极大地增
进IBL实时渲染效率。

漫反射光照之所以能够预先计算辐照度图，是因为其积分计算仅依赖于入射光线方向$\omega_{i}$。但是镜面反射积分计算既依赖于$\omega_{i}$，
也依赖于观察方向$\omega_{0}$，而对每种可能的$\omega_{i}$与$\omega_{0}$组合预计算积分是极为困难的。为此，我们利用分割求和近
似法，如公式\ref{equation:split-sum}，拆解镜面反射积分为光照与BRDF两个独立积分，分别对两者预先计算，最后组合得到镜面反射结
果。这种近似求解方案在准确性上可能导致一些误差，但出于实时计算的要求，这种误差是可以接受的。

\begin{equation}
	\label{equation:split-sum}
	L_{0}(p,\omega_{0})=\int_{\Omega }L_{i}(p,\omega_{i})n\cdot w_{i}d\omega_{i}*\int_{\Omega }f_{r}(p,\omega_{i},\omega_{0})n\cdot w_{i}d\omega_{i}
\end{equation}

除此之外，不同于漫反射光照的均匀分布，镜面反射的分布依赖于物体表面粗糙程度与入射光线方向，大多数光线会集中反射于围绕微平面中间
向量的一个高光波瓣中，如图\ref{fig:lobe}所示。基于此观察，本文提出了一种GGX重要性采样的镜面高光计算方法，通过向高光波瓣处偏置
采样向量，进而加快收敛速度，提高渲染效率。

\begin{figure*}[htbp]
    \centering
    \includegraphics[width=\linewidth]{Figures/chapter_3/lobe.png}
    \caption{镜面波瓣}
    \label{fig:lobe}
\end{figure*}


\subsection{本文算法流程}

本文针对IBL间接光照进行改进，算法流程主要步骤包括创建镜面反射光照预滤波环境贴图和创建镜面反射BRDF2D查找纹理。详细步骤如下：

针对漫反射光照部分，预计算漫反射辐照度贴图。首先捕获环境贴图，在场景中心渲染一个单位立方体，从环境贴图中采样光照。然后使用
黎曼和方法均匀的生成采样向量，并进行卷积，生成辐照度贴图。

针对镜面高光部分，本文算法使用分割求和近似法，将其拆解为光照和BRDF两个独立的积分，分别对其进行预计算。对于光照部分，类似于
漫反射辐照图，渲染一个立方体，从环境贴图采样光照信息，卷积后生成预滤波环境贴图。唯一不同的是，漫反射辐照度图使用均匀采样采
样光照信息，而镜面光照采用GGX重要性采样技术，集中采样在镜面波瓣处。对于BRDF部分，创建一张称为BRDF查找纹理的2D纹理贴图，储
存其卷积结果。

最后，在获得漫反射辐照度图、预滤波环境贴图以及二维查找纹理后，便可根据公式相乘求和，得到最终的环境光照。

\begin{figure*}[htbp]
    \centering
    \includegraphics[width=\linewidth]{Figures/chapter_3/AlgorithmFlow.png}
    \caption{间接光照算法流程}
    \label{fig:flow}
\end{figure*}

\section{算法核心细节}
\label{secAlgorithmDetail}

\subsection{GGX重要性采样}
镜面反射在实际中并不是均匀分布，它依赖于特定的入射光线方向和物体表面的粗糙程度,其反射光会呈现出不同的发散程度,如图\ref{fig:lobe}所示。
反射光的分布形状称为高光波瓣(specular lobe)，它随着表面粗糙度变化而变化，粗糙度越大，高光波瓣也越大。

对于镜面光反射部分，当涉及到微表面模型时，可以把高光波瓣当作在给定入射光方向的微平面上的反射方向。由于大多数光线最终会
反射到围绕微平面中间量的一个高光波瓣中，所以需要以高光波瓣形状相似的方式生成采样向量。注意这里不同于漫反射辐照度的地方
是应该用光照向量当作采样向量从环境贴图中取值，而非物体表面的法线向量。

使用蒙特卡洛方法可以将积分问题转化为数学期望的求解。对于方程\ref{equation:specular}有
\begin{equation}
	L_{0}\thickapprox \frac{1}{N}\sum_{0}^{N}\frac{F(h,v)G(l,v)L_{i}v\cdot h}{(v\cdot n)(n\cdot h)}
\end{equation}

分析上式可知菲涅尔方程F与半程向量$\emph{h}$、观察向量$\emph{v}$有关，几何遮蔽函数G与观察方向$\emph{v}$、入射光方向$\emph{l}$有关。因为最终是要使用入射光向
量从环境贴图中采样，在运行时可以获取到观察方向$\emph{v}$，而入射光方向$\emph{l}$与半程向量$\emph{h}$知道一个就可以算出另外一个。入射光方向不容易直
接生成，考虑到高光波瓣的形状与粗糙度有关，即受微平面的法线分布影响，这样就需引入法线分布函数D(h)，根据重要性采样来生成
半程向量$\emph{h}$。
微平面半程向量的球面坐标如下：
\begin{equation}
	\begin{split}
		\theta &=\arccos \sqrt{\frac{1-x}{(a^2-1)x+1}}\\
	    \phi &=2\pi y
	\end{split}
\end{equation}
其中(x,y)是二维平面向量,$\emph{a}$一般使用粗糙度的平方。将生成的半程向量转换至世界坐标系之后，便可生成入射光向量进行采样。
具体流程如算法\ref{aig:ImportanceSampling}所示：

\begin{algorithm} 
	\caption{重要性采样}  
	\label{aig:ImportanceSampling}
		\begin{algorithmic}[1] %每行显示行号  
			\Require 随机向量$x_{i}$，表面法线向量$\emph{n}$, 粗糙度系数$roughness$,观察向量$\emph{v}$
			\Ensure 采样向量$\emph{l}$
			\State  生成半程向量$\emph{h}$
			\State  将$\emph{h}$从球面坐标系转换至笛卡尔坐标系
			\State  将$\emph{h}$从切线空间转换至世界空间
			\State  生成采样向量$\emph{l}$:$\emph{l}=2*\emph{v}\cdot \emph{h}*\emph{h}-\emph{v}$
		\end{algorithmic}  
	\end{algorithm} 

在使用蒙特卡洛方法和重要性采样之后，仍需要采集大量样本。为了获得足够精细的光照效果，每个片段仍需要大于16的采样数量。在实时渲
染中，这对于每个片段着色器是不能承担的计算量。这就需要一种类似漫反射光照部分的预计算方法，将采样所得光照值存储起来。


\subsection{分割求和近似}

正如公式\ref{equation:split-sum}所示，分割求和近似将镜面光照部分拆解为了两个独立的积分，这样便允许我们分别对其进行预计算。
对于前半部分，即入射光的辐射亮度，其预计算类似于漫反射光照，卷积后生成一张类似于辐照度贴图的预滤波环境贴图。对于后半部分，该
积分表示双向反射分布函数的镜面反射积分，其预计算以粗糙度和入射角为组合，存储BRDF对每一组合的卷积结果至一张2D查找纹理上，
称之为BRDF积分贴图。

\subsubsection{预滤波环境贴图}
预滤波环境贴图的计算与漫反射辐照度贴图的计算方式相似，计算结果也十分相似。但区别于漫反射光照卷积时的均匀采样，做为镜面光照
的预滤波环境贴图，其入射光方向依赖于物体表面粗糙度，即微平面上的半程向量。在生成采样向量时，需根据粗糙度和低差异序列值向量，
生成一个围绕半程向量的采样向量，以保证采样向量基本处于镜面波瓣内。

除此之外，由于执行的是预计算，我们无法提前获取表面粗糙度系数。因此，为保证不同粗糙度系数下均能正确采样，我们为预滤波环境贴
图生成mipmap（多级渐远纹理），运行时根据粗糙度系数向对应的mip等级的纹理采样即可。与之相同的是，视角方向$v$也无法提前获取。
为此，我们假设视角方向$v$等于输出采样方向$w_{0}$。这通常会导致从掠角方向(与表面法线垂直时)观察时，镜面反射效果不佳。但是这
种现象只在某些特定情况下才较易观察，尤其在球面上并不明显。总的来说，这种计算妥协是十分值得的。



\subsubsection{预计算BRDF}

\begin{figure*}[htbp]
    \centering
    \includegraphics[width=0.5\linewidth]{Figures/chapter_3/BRDF.png}
    \caption{BRDF积分贴图}
    \label{fig:BRDF}
\end{figure*}

对于环境BRDF部分来说有：
\begin{equation}
	\int_{\Omega }f_{r}(p,\omega_{i},\omega_{0})n\cdot w_{i}d\omega_{i}=\int_{\Omega }f_{r}(p,\omega_{i},\omega_{0})\frac{F(\omega_{0},h)}{F(\omega_{0},h)}n\cdot w_{i}d\omega_{i}
\end{equation}

代入菲涅尔方程，可得：
\begin{equation}
	\label{equation:BRDF}
	\int_{\Omega }f_{r}(p,\omega_{i},\omega_{0})n\cdot w_{i}d\omega_{i}
	=\int_{\Omega }f_{r}(p,\omega_{i},\omega_{0})(1-(1-\omega_{0}\cdot h)^{5})n\cdot w_{i}d\omega_{i}
	+\int_{\Omega }f_{r}(p,\omega_{i},\omega_{0})(1-\omega_{0}\cdot h)^{5}n\cdot w_{i}d\omega_{i}
\end{equation}

这是一个关于$F_{0}$的函数，其中$F_{0}$为常量，可写成：
\begin{equation}
	\int_{\Omega }f_{r}(p,\omega_{i},\omega_{0})n\cdot w_{i}d\omega_{i}
	=F_{0}\cdot scale
	+bias
\end{equation}

两个积分项分别为$F_{0}$的缩放量和偏移量，因此渲染时只需求出该两项便可求得环境BRDF项。从公式\ref{equation:BRDF}中可知，
对其求解需要知道表面法线向量$\emph{n}$，视角向量$\omega_{0}$,半程向量$\emph{h}$，入射光向量$\omega_{i}$和表面粗糙度$\alpha$。
半程向量$\emph{h}$可由重要性采样得到。至于视角向量$\omega_{0}$和入射光向量$\omega_{i}$，由于是在切线空间预计算，表面法线向量$\emph{n}$
始终为$(0,0,1)$，故只需知道$\emph{n}$与$\omega_{0}$的夹角便可解得视角向量$\omega_{0}$与入射光向量$\omega_{i}$。

综上所述，输入$\emph{n}$与$\omega_{0}$夹角，输出缩放量scale和偏移量bias两项的结果，结果存储在一张二维纹理贴图上，称之为
BRDF积分贴图。$\emph{n}$与$\omega_{0}$夹角与粗糙度$\alpha$做为纹理贴图的（u,v）坐标，scale和bias做为纹理像素的颜色值，使用
（r，g）通道来存储,如图\ref{fig:BRDF}所示。

